﻿using System;
using System.Diagnostics;
using System.Xml;

namespace MockingBird.Simulator.Framework
{
    using System.Threading;
    using Common.Infrastructure.DependencyResolution;
    using Common.Infrastructure.Logging;
    using Exceptions;
    using Interfaces;
    using Microsoft.Practices.Unity;


    public class RequestDistributor : IRequestDistributor
    {
        #region "private members - dependencies"
        private IExecutionContext context;
        private ILogger logger;
        private IHandlerDispenser handlerDispenser;
        #endregion

        #region "properties"
        public IMessageHandler MessageHandler { private get; set; }
        #endregion

        #region "constructor(s)"
        [InjectionConstructor]
        public RequestDistributor(IExecutionContext execContext, ILogger logger, IHandlerDispenser dispenser)
        {
            Debug.WriteLine(string.Format("RequestDistributor.ctor on thread ID: {0}", Thread.CurrentThread.ManagedThreadId));
            if (execContext == null)
                throw new ArgumentNullException("execContext", "execContext is null.");
            //assign the incoming data to the members
            this.context = execContext;
            this.logger = logger;
            this.handlerDispenser = dispenser;
        }

        #endregion

        #region "implementation"

        /// <summary>
        /// Processes the request using the specific incoming context.
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public XmlDocument ProcessRequest(IExecutionContext context)
        {
            // Overwrite the existing context and delegate to overloaded method.
            this.context = context;
            return this.ProcessRequest();
        }
        /// <summary>
        /// Processes the request and hands off to the appropriate handler
        /// </summary>
        public XmlDocument ProcessRequest()
        {
            if (logger == null)
            {
                logger = DependencyResolver.DefaultContainer.Resolve<ILogger>();
            }
            //make a call to the logger
            logger.Log("RequestDistributor:Process Request");
            logger.Log("Endpoint Full Name : " + context.EndpointFullName);

            //if the dispenser hasnt been injected, then create a new one
            if (this.handlerDispenser == null)
            {
                this.handlerDispenser = DependencyResolver.DefaultContainer.Resolve<IHandlerDispenser>();
            }

            //get the handler from the dispenser
            this.logger.LogInfo("Getting a handler from the dispenser");
            this.MessageHandler = this.handlerDispenser.GetHandler(context);

            if (this.MessageHandler == null)
            {
                throw new ApplicationOperationException("could not locate handler for specified endpoint :" +
                                                        context.EndpointFullName);
            }

            //Call the handle message method on the handler
            try
            {
                this.logger.LogInfo("Calling the handle message");
                this.MessageHandler.HandleMessage(context);
                return context.ResponseMessage;
            }
            catch (ApplicationOperationException aEx)
            {
                LogException(aEx);
                throw;
            }
            catch (ApplicationConfigurationException conEx)
            {
                LogException(conEx);
                throw;
            }
            catch (HandlerConfigurationException handlerConEx)
            {
                LogException(handlerConEx);
                throw;
            }

        }

        #endregion

        #region "private methods"
        private void LogException(Exception e)
        {
            logger.LogFatal("Request Distributor: An exception occurred in your application", e);


        }
        #endregion
    }
}
